#!/usr/bin/env bash

if [ "$(id -u)" = "0" ]; then
	echo "Switching to dedicated user 'mysql'"
	exec gosu mysql "$BASH_SOURCE" "$@"
fi

# usage: file_env VAR [DEFAULT]
#    ie: file_env 'XYZ_DB_PASSWORD' 'example'
# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
#  "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
file_env() {
	local var="$1"
	local fileVar="${var}_FILE"
	local def="${2:-}"
	if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
		mysql_error "Both $var and $fileVar are set (but are exclusive)"
	fi
	local val="$def"
	if [ "${!var:-}" ]; then
		val="${!var}"
	elif [ "${!fileVar:-}" ]; then
		val="$(< "${!fileVar}")"
	fi
	export "$var"="$val"
	unset "$fileVar"
}

# set MARIADB_xyz from MYSQL_xyz when MARIADB_xyz is unset
# and make them the same value (so user scripts can use either)
_mariadb_file_env() {
	local var="$1"; shift
	local maria="MARIADB_${var#MYSQL_}"
	file_env "$var" "$@"
	file_env "$maria" "${!var}"
	if [ "${!maria:-}" ]; then
		export "$var"="${!maria}"
	fi
}

# SQL escape the string $1 to be placed in a string literal.
# escape, \ followed by '
docker_sql_escape_string_literal() {
	local newline=$'\n'
	local escaped=${1//\\/\\\\}
	escaped="${escaped//$newline/\\n}"
	echo "${escaped//\'/\\\'}"
}

mysql_get_config() {
	local conf="$1"; shift
	mysqld --verbose --help 2>/dev/null \
		| awk -v conf="$conf" '$1 == conf && /^[^ \t]/ { sub(/^[^ \t]+[ \t]+/, ""); print; exit }'
}

# Build env vars
DATADIR="$(mysql_get_config 'datadir')"
SOCKET="$(mysql_get_config 'socket')"

_mariadb_file_env 'MYSQL_ROOT_HOST' '%'
_mariadb_file_env 'MYSQL_ROOT_PASSWORD'

: "${MARIADB_ALLOW_EMPTY_ROOT_PASSWORD:=${MYSQL_ALLOW_EMPTY_PASSWORD:-}}"
export MYSQL_ALLOW_EMPTY_PASSWORD="$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" MARIADB_ALLOW_EMPTY_ROOT_PASSWORD
: "${MARIADB_RANDOM_ROOT_PASSWORD:=${MYSQL_RANDOM_ROOT_PASSWORD:-}}"
export MYSQL_RANDOM_ROOT_PASSWORD="$MARIADB_RANDOM_ROOT_PASSWORD" MARIADB_RANDOM_ROOT_PASSWORD
: "${MARIADB_INITDB_SKIP_TZINFO:=${MYSQL_INITDB_SKIP_TZINFO:-}}"
export MYSQL_INITDB_SKIP_TZINFO="$MARIADB_INITDB_SKIP_TZINFO" MARIADB_INITDB_SKIP_TZINFO

if [ -z "$MARIADB_ROOT_PASSWORD" -a -z "$MARIADB_ALLOW_EMPTY_ROOT_PASSWORD" -a -z "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then
	mysql_error $'Database is uninitialized and password option is not specified\n\tYou need to specify one of MARIADB_ROOT_PASSWORD, MARIADB_ALLOW_EMPTY_ROOT_PASSWORD and MARIADB_RANDOM_ROOT_PASSWORD'
fi

# Spin up temp server
echo "Starting temporary MariaDB server..."

mysqld --skip-networking --skip-grant-tables --socket="${SOCKET}" &

echo "Waiting for server startup"
for i in {30..0}; do
	if mysql --protocol=socket -hlocalhost -uroot --socket="${SOCKET}" --database=mysql <<<'SELECT 1'; then
		break
	fi
	sleep 1
done
if [ "$i" = 0 ]; then
	echo "Unable to start temporary server."
	exit 1
fi

# Try password reset
echo "Resetting root password..."

if [ -n "$MARIADB_RANDOM_ROOT_PASSWORD" ]; then
	MARIADB_ROOT_PASSWORD="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)"
	export MARIADB_ROOT_PASSWORD MYSQL_ROOT_PASSWORD=$MARIADB_ROOT_PASSWORD
	echo "GENERATED ROOT PASSWORD: $MARIADB_ROOT_PASSWORD"
fi

# Sets root password and creates root users for non-localhost hosts
rootCreate=
rootPasswordEscaped=$( docker_sql_escape_string_literal "${MARIADB_ROOT_PASSWORD}" )

# default root to listen for connections from anywhere
if [ -n "$MARIADB_ROOT_HOST" ] && [ "$MARIADB_ROOT_HOST" != 'localhost' ]; then
	# no, we don't care if read finds a terminating character in this heredoc
	# https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
	read -r -d '' rootCreate <<-EOSQL || true
		ALTER USER 'root'@'${MARIADB_ROOT_HOST}' IDENTIFIED BY '${rootPasswordEscaped}' ;
		GRANT ALL ON *.* TO 'root'@'${MARIADB_ROOT_HOST}' WITH GRANT OPTION ;
	EOSQL
fi

# tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set
# --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding.
mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" --database=mysql --binary-mode <<-EOSQL
	FLUSH PRIVILEGES ;
	ALTER USER 'root'@'localhost' IDENTIFIED BY '${rootPasswordEscaped}' ;
	GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;

	${rootCreate}
EOSQL

echo "Password reset complete."
